﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Evaluant.Uss.ObjectContext;
using Evaluant.Uss.ObjectContext.Services;
using NUnit.Mapping.Domain;

namespace NUnit.PersistenceManager
{
    public delegate void VisitPerson(Person p);

    class NUnitService : IService
    {
        protected bool isRegistered;
        public bool IsRegistered
        {
            get { return isRegistered; }
        }

        public event VisitPerson BeforeOperation;

        protected int visited;
        public int Visited
        {
            get { return visited; }
            set { visited = value; }
        }

        #region IService Membres

        public void ServiceAdded()
        {
            isRegistered = true;
        }

        public void ServiceRemoved()
        {
            isRegistered = false;
        }

        public void Visit(object item, ServiceContext context)
        {
            visited++;
            switch (context.Operation)
            {
                case Operation.Inserting:
                case Operation.Updating:
                    if (BeforeOperation != null && item is Person)
                    {
                        BeforeOperation(item as Person);
                        context.EntityChanged = true;
                    }
                    break;
                default:
                    break;
            }
        }

        public void Visit(object parent, object child, ReferenceServiceContext context)
        {
            visited++;
            switch (context.Operation)
            {
                case Operation.Inserting:
                case Operation.Updating:
                case Operation.Deleting:
                case Operation.CreatingRelationship:
                case Operation.RemovingRelationship:
                    if (BeforeOperation != null && parent is Person)
                    {
                        BeforeOperation(parent as Person);
                        context.ParentEntityChanged = true;
                    }
                    break;
                default:
                    break;
            }

        }

        #endregion
    }

    [TestClass]
    public class ServicesAndEvents
    {
        private static ObjectService os;
        private ObjectContext oc;
        NUnitService service;
        bool registered = false;

        [TestInitialize]
        public void Initialize()
        {
            if (os == null)
                os = new ObjectService("engines.config", "Core");
            service = new NUnitService();
            os.AddService(service);
            oc = os.CreateObjectContext();
            oc.InitializeRepository();
            oc.EnableEvents = true;
        }

        [TestMethod]
        public void ShouldAddService()
        {
            Assert.IsTrue(service.IsRegistered);
            os.RemoveService(service);
            Assert.IsFalse(service.IsRegistered);
            oc.AddService(service);
            Assert.IsTrue(service.IsRegistered);
        }

        [TestMethod]
        public void ShouldBeCalledOnOperation()
        {
            Assert.IsTrue(service.IsRegistered);
            oc.BeginTransaction();
            Person p = new Person();
            p.FirstName = "Nicolas";
            oc.Serialize(p);
            oc.CommitTransaction();
            //Inserting & Inserted
            Assert.AreEqual(2, service.Visited);
            oc.Clear();
            p = oc.LoadSingle<Person>();
            //Loaded
            Assert.AreEqual(3, service.Visited);
            p.LastName = "Penin";
            oc.BeginTransaction();
            oc.Serialize(p);
            oc.CommitTransaction();
            //Updating & Updated
            Assert.AreEqual(5, service.Visited);
            oc.BeginTransaction();
            oc.Delete(p);
            oc.CommitTransaction();
            //Deleting & Deleted
            Assert.AreEqual(7, service.Visited);
        }

        [TestMethod]
        public void EntityShouldBeChangedIfChangedInEvent()
        {
            registered = true;
            service.BeforeOperation += new VisitPerson(service_BeforeOperation);
            Person p = new Person();
            p.FirstName = "Nicolas";
            oc.BeginTransaction();
            oc.Serialize(p);
            oc.CommitTransaction();
            Assert.AreEqual((service.Visited - 1).ToString(), p.LastName);
            oc.Clear();
            p = oc.LoadSingle<Person>();
            Assert.AreEqual((service.Visited - 2).ToString(), p.LastName);
            p.FirstName = "Nico";
            oc.BeginTransaction();
            oc.Serialize(p);
            oc.CommitTransaction();
            Assert.AreEqual((service.Visited - 1).ToString(), p.LastName);
            registered = false;
        }

        void service_BeforeOperation(Person p)
        {
            if (registered)
                p.LastName = service.Visited.ToString();
        }
    }
}
